#pragma once

#include <iostream>
#include <pthread.h>
#include <string>
#include <vector>
#include <sstream>
#include <unistd.h>
#include <fstream>
#include "Socket.hpp"
#include "log.hpp"

static const uint16_t defaultport = 9000;

const std::string wwwroot = "wwwroot"; // web根目录
const std::string homePage = "index.html";
const std::string endSep = "\r\n";

class HttpServer;

class ThreadData
{
public:
    ThreadData(int sock, HttpServer *hs) : m_sock(sock), m_httpsvr(hs)
    {
    }

public:
    int m_sock;
    HttpServer *m_httpsvr;
};

class HttpRequest
{
public:
    void Deserialize(std::string req)
    {
        while (true)
        {
            size_t pos = req.find(endSep);
            if (pos == std::string::npos)
                break;
            std::string temp = req.substr(0, pos);
            if(temp.empty()) break;

            m_reqHeader.push_back(temp);
            req.erase(0, pos + endSep.size());
        }
        m_text = req;
    }

    void Parse()
    {
        std::stringstream ss(m_reqHeader[0]);
        ss >> m_method >> m_url >> m_version;
        m_resourcePath = wwwroot;
        if(m_url == "/" || m_url == "/index.html")
        {
            m_resourcePath += '/';
            m_resourcePath += homePage;
        }
        else
            m_resourcePath += m_url;    
    }

    void DebugPrint()
    {
        for(auto & line : m_reqHeader)
        {
            std::cout << "---------------------------------" << std::endl;
            std::cout << line << "\n\n";
        }
        std::cout << "method: " << m_method << std::endl;
        std::cout << "url: " << m_url << std::endl;
        std::cout << "version: " << m_version << std::endl;
        std::cout << "resourcePath: " << m_resourcePath << std::endl;
        std::cout << m_text << std::endl;
    }

public:
    std::vector<std::string> m_reqHeader; // 请求行
    std::string m_text;                   // 请求正文

    // 解析之后的结果
    std::string m_method;
    std::string m_url;
    std::string m_version;
    std::string m_resourcePath;
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport) : m_port(port) {}

    void Start()
    {
        m_listensock.Socket();
        m_listensock.Bind(m_port);
        m_listensock.Listen();

        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int newfd = m_listensock.Accept(&clientip, &clientport);
            if (newfd < 0)
            {
                continue;
            }
            log(INFO, "get a new connect, newfd: %d", newfd);
            pthread_t tid;
            ThreadData *td = new ThreadData(newfd, this);
            pthread_create(&tid, nullptr, ThreadRoutine, td);
        }
    }

    static std::string ReadHtmlContent(const std::string &htmlpath)
    {
        std::ifstream in(htmlpath);
        if (!in.is_open())
            return "404";

        std::string content;
        std::string line;
        while (std::getline(in, line))
        {
            content += line;
        }
        in.close();
        return content;
    }

    static void HandlerHttp(int sockfd)
    {
        char buffer[10240];
        int n = recv(sockfd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << buffer; // 假设走到这里我们读取到的就是一个完整的http请求
            HttpRequest req;
            std::string url;
            req.Deserialize(buffer);
            req.Parse();
            // req.DebugPrint();

            // 获取客户端请求的资源路径
            // std::string path = "wwwroot/";
            // path += url; // "wwwroor/请求的路径"

            // 返回响应的过程
            // std::string text = "<html><body><h3>hello world</h3></body></html>";
            // std::string text = ReadHtmlContent("wwwroot/index.html");
            std::string text = ReadHtmlContent(req.m_resourcePath);
            std::string response_line = "HTTP/1.1 200 OK\r\n";
            std::string response_header = "Content-Length: ";
            response_header += std::to_string(text.size());
            response_header += "\r\n";
            std::string blank_line = "\r\n";

            std::string response = response_line;
            response += response_header;
            response += blank_line;
            response += text;

            send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd);
    }

    static void *ThreadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        HandlerHttp(td->m_sock);
        delete td;
        return nullptr;
    }

    ~HttpServer() {}

private:
    Sock m_listensock;
    uint16_t m_port;
};